/*  NeoBan
cvars:
amx_neoban_action (1) - akcja po zbanowainu
	1 - kick z info w konsoli
	2 - kick bez info
	3 - exit
	4 - nic - mozna go zbanowac normalnie
	5 - brak obrazen
	6 - kick z info z z CVAR'a amx_neoban_reason1
	
amx_neoban_action_connect (1) - akcja uykonywana jesli zbanowany gracz sie polaczy
	1 - kick z info w konsoli
	2 - kick bez info
	3 - exit
	4 - nic
	5 - brak obrazen
	6 - kick z info z z CVAR'a amx_neoban_reason2
	
amx_neoban_url ("www.wypad_czicie.com") - adres forum

amx_neoban_info ("cs_num") - nazwa info (anjlepiej aby byla unikalna dla kazdego serwera)

amx_neoban_reason1 ("Wyrzucony z powodu rezerwacji slotow") - inforamcja wyswietlana jesli gracz zostanie zbanowany
amx_neoban_reason2 ("Serwer w trakcie modernizcaji. Zapraszamy wkrotce.") - inforamcja wyswietlana po polaczeniu jesli gracz jest zbanowany

komendy:
	amx_neobanmenu
	amx_neounbanmenu

*/

#include <amxmodx>
#include <amxmisc>
#include <nvault>
#include <hamsandwich>

#define PLUGIN "Neo Ban"
#define VERSION "1.0"
#define AUTHOR "Tequila aka Zabijaka"
#define NAME_LEN 64
#define INFO_LEN 6
#define INFO_NAME_LEN 16
#define TASK_CHECK_BAN 100
#define TASK_WRITE_BAN 200
#define IsPlayer(%1) (1<= %1 <= g_iMaxPlayers)


new gCvarAction;
new gCvarActionConnect;
new gCvarInfo;
new gCvarUrl;
new gCvarReason1;
new gCvarReason2;

new gVault;
new const NEXT_BAN_ID[] ="NEXT_BAN_ID";
new Array:gConfigs;
new gMaxConfigs;
new infoName[INFO_NAME_LEN];
new nextBanId = 1;
new gUrl[128];

new gPowodyBanow[7][64];
new gPowodyCzasyBanow[7];
new gCzasyBanow[7];
new gIloscPowodow;
new gIloscCzasow;

new zbanowany[33];
new banMenuGracz[33];
new banMenuCzas[33];
new banMenuPowod[33][64];

new g_iMaxPlayers;

public plugin_init() {
	register_plugin(PLUGIN, VERSION, AUTHOR);
	g_iMaxPlayers = get_maxplayers();
	
	gCvarInfo =  register_cvar("amx_neoban_info", "cs_num");
	gCvarAction  = register_cvar("amx_neoban_action", "1");
	gCvarActionConnect  = register_cvar("amx_neoban_action_connect", "1");
	gCvarUrl =  register_cvar("amx_neoban_url", "www.wypad_czicie.com");
	RegisterHam(Ham_TakeDamage, "player", "fwd_Ham_TakeDamage");
	
	gVault = nvault_open("NeoBans");
	new banId[16];
	new timestamp;
	if(nvault_lookup(gVault, NEXT_BAN_ID, banId, charsmax(banId), timestamp)){
		nextBanId = str_to_num(banId);
	}
	gConfigs = ArrayCreate(32);
	new cfgDir[128];
	new neoBansConfigFile[128];
	get_configsdir(cfgDir, charsmax(cfgDir));
	
	format(neoBansConfigFile, charsmax(neoBansConfigFile), "%s\neobans\neo_bans_configs.ini", cfgDir);
	get_configs(neoBansConfigFile);
	
	format(neoBansConfigFile, charsmax(neoBansConfigFile), "%s\neobans\neo_bans_powody.ini", cfgDir);
	get_powody(neoBansConfigFile);
	
	format(neoBansConfigFile, charsmax(neoBansConfigFile), "%s\neobans\neo_bans_czasy.ini", cfgDir);
	get_czasy(neoBansConfigFile);
	
	format(neoBansConfigFile, charsmax(neoBansConfigFile), "%s\neobans\neo_bans.cfg", cfgDir);
	server_cmd("exec %s", neoBansConfigFile);
	
	register_clcmd("amx_neobanmenu", "banNeoMenu", ADMIN_BAN);
	register_clcmd("amx_neoban_powod", "banNeoPowod", ADMIN_BAN);
	register_clcmd("amx_neounbanmenu", "unbanNeoMenu", ADMIN_BAN);
	register_srvcmd("amx_neoban", "banNeoServer");
}
public banNeoServer(){
	

}

public TakeDamage(id, idinflictor, idattacker, Float:damage, damagebits){
	if(get_pcvar_num(gCvarAction) == 5){
		if(IsPlayer(idattacker)){
			if(zbanowany[idattacker]){
				SetHamParamFloat(4, 0.0);
			}
		}
	}
	return HAM_IGNORED;
}

public plugin_cfg() {
	
	get_pcvar_string(gCvarInfo, infoName, INFO_NAME_LEN -1);
	get_pcvar_string(gCvarUrl, gUrl, charsmax(gUrl));
}

stock get_powody(const cfgFile[]){
	if(file_exists(cfgFile)){
		new data[32]
		new f = fopen(cfgFile, "rt")
	
		new czas[10];
		new powod[64];
		
		while( !feof(f) && gIloscPowodow<7 ) {
			fgets(f, data, sizeof(data) - 1);
			trim(data);
			if( !data[0] || data[0] == ';' || (data[0] == '/' && data[1] == '/' )) 
				continue;
			split(data, czas, charsmax(czas), powod, charsmax(powod), " ");
			if(is_str_num(czas)){
				gPowodyCzasyBanow[gIloscPowodow] = str_to_num(czas);
				copy(gPowodyBanow[gIloscPowodow], NAME_LEN-1, powod);
				gIloscPowodow++;
			}
		}
		fclose(f) ;
	}
	if(gIloscPowodow==0) {
		
		gPowodyCzasyBanow[gIloscPowodow] = 0;
		copy(gPowodyBanow[gIloscPowodow], NAME_LEN-1, "Czitujesz");
		gIloscPowodow++;
		
		gPowodyCzasyBanow[gIloscPowodow] = 10;
		copy(gPowodyBanow[gIloscPowodow],  NAME_LEN-1, "Lagujesz. Ogarnij Ping.");
		gIloscPowodow++;
		
		gPowodyCzasyBanow[gIloscPowodow] = 30;
		copy(gPowodyBanow[gIloscPowodow],  NAME_LEN-1, "Cele Mapy!");
		gIloscPowodow++;
		
		gPowodyCzasyBanow[gIloscPowodow] = 60;
		copy(gPowodyBanow[gIloscPowodow],  NAME_LEN-1, "Kultura!");
		gIloscPowodow++;
		
		gPowodyCzasyBanow[gIloscPowodow] = 60;
		copy(gPowodyBanow[gIloscPowodow], NAME_LEN-1, "Utrudniasz gre innym!");
		gIloscPowodow++;
		
		gPowodyCzasyBanow[gIloscPowodow] = -2;
		copy(gPowodyBanow[gIloscPowodow],  NAME_LEN-1, "Wlasny powod");
		gIloscPowodow++;
	}
}

stock get_czasy(const cfgFile[]){
	if(file_exists(cfgFile)){
		new data[32]
		new f = fopen(cfgFile, "rt")
	
		while( !feof(f) && gIloscCzasow<7 ) {
			fgets(f, data, sizeof(data) - 1);
			trim(data);
			if( !data[0] || data[0] == ';' || (data[0] == '/' && data[1] == '/' )) 
				continue;
			if(is_str_num(data)){
				gCzasyBanow[gIloscCzasow] = str_to_num(data);
				if(gCzasyBanow[gIloscCzasow]  >=0){
					gIloscCzasow++;
				}
			}
		}
		fclose(f) ;
	}
	if(gIloscCzasow==0) {
		
		gCzasyBanow[gIloscCzasow] = 0; //perm
		gIloscCzasow++;
		
		gCzasyBanow[gIloscCzasow] = 10; //10 minut
		gIloscCzasow++;
		
		gCzasyBanow[gIloscCzasow] = 30; //30 minut
		gIloscCzasow++;
		
		gCzasyBanow[gIloscCzasow] = 60; // 1 godzina
		gIloscCzasow++;
		
		gCzasyBanow[gIloscCzasow] = 60 * 24; //1 dzien
		gIloscCzasow++;
		
		gCzasyBanow[gIloscCzasow] = 60 * 24 * 7; // 1 tydzien
		gIloscCzasow++;
	}
}

stock get_configs(const cfgFile[]){
	if(file_exists(cfgFile)){
		new data[32]
		new f = fopen(cfgFile, "rt")
		
		while( !feof(f) ) {
			fgets(f, data, sizeof(data) - 1);
			trim(data);
			if( !data[0] || data[0] == ';' || (data[0] == '/' && data[1] == '/' )) 
				continue;
			ArrayPushString(gConfigs, data);
			gMaxConfigs++;
		}
		fclose(f) ;
	}
	if(gMaxConfigs==0){
		ArrayPushString(gConfigs,"maps\de_mp");
		ArrayPushString(gConfigs,"maps\usercfg");
		ArrayPushString(gConfigs,"usercfg");
		ArrayPushString(gConfigs,"config_bak");
		ArrayPushString(gConfigs,"save\config_bak");
		ArrayPushString(gConfigs,"hl");
		ArrayPushString(gConfigs,"cs");
		gMaxConfigs = 7;
	}
}

public client_putinserver(id){
	if(is_user_connected(id) && !is_user_bot(id) && !is_user_hltv(id)){
		new taskInfo[3];
		taskInfo[0] = id;
		taskInfo[1] = 0;
		set_task(0.01,"read_ban_cfg", id+ TASK_CHECK_BAN, taskInfo, 3);
	}
	zbanowany[id] = 0;
	banMenuCzas[id] = 0;
	banMenuGracz[id] = 0;
	banMenuPowod[id][0] = 0;
}
public client_disconnect(id){
	zbanowany[id] = 0;
}

public read_ban_cfg(taskInfo[]){
	new id = taskInfo[0];
	
	if(!is_user_connected(id))
		return;
	client_cmd(id, "clear");
	new banId = check_ban(id);
	if(banId > 0) {
		process_ban(id, banId, true);
	} else {
		if(taskInfo[1] < gMaxConfigs) {
			new cfg[32];
			ArrayGetString(gConfigs, taskInfo[1], cfg, charsmax(cfg));
			taskInfo[1] = taskInfo[1] + 1;
			client_cmd(id, "exec %s.cfg", cfg);
			set_task(0.01, "read_ban_cfg", id + TASK_CHECK_BAN, taskInfo, 3);
		} else {
			client_cmd(id, "exec config.cfg");
		}
	}
}

public check_ban(id) {
	if(!is_user_connected(id))
		return -1;
		
	new info[INFO_LEN]
	get_user_info(id, infoName, info, INFO_LEN -1);
	if(info[0] != 0 && is_str_num(info)) {
		new banTimeStr[64];
		new timestamp;
		if(nvault_lookup(gVault, info, banTimeStr, INFO_LEN -1, timestamp)){
			new czasInt = str_to_num(banTimeStr) * 60;
			if(czasInt == 0  || (timestamp + czasInt > get_systime())){
				return str_to_num(info);
			} else {
				unban_id(str_to_num(info));
			}
		}
	}
	return 0;
}

stock unban_id(banId){
	new info[32];
	num_to_str(banId, info, charsmax(info));
	nvault_remove(gVault, info); //czas bana
	
	new infoTmp[64];
	formatex(infoTmp, 63, "%s_a", info); //admin banujacy
	nvault_remove(gVault, infoTmp);
	
	infoTmp[0] =0;
	formatex(infoTmp, 63, "%s_r", info); // powod bana
	nvault_remove(gVault, infoTmp);
	
	infoTmp[0] =0;
	formatex(infoTmp, 63, "%s_n", info); // nick zbanowanego
	nvault_remove(gVault, infoTmp);
}

stock process_ban(id, banId, bool:onConnect){
	client_cmd(id, "setinfo ^"%s^" ^"%d^"",infoName, banId);
	zbanowany[id] = 1;
	new taskInfo[5];
	taskInfo[0] = id;
	taskInfo[1] = banId;
	taskInfo[2] =( onConnect ? 1 : 2);
	taskInfo[3] = 0;	
	set_task(0.01, "write_ban_cfg", id + TASK_WRITE_BAN, taskInfo, 5);
}


public delayed_kick(taskInfo[]){
	new id = taskInfo[0];	
	
	if(!is_user_connected(id))
		return;
	new action;
	if(taskInfo[2] == 1)
		action = get_pcvar_num(gCvarActionConnect);
	else
		action = get_pcvar_num(gCvarAction);
		
	switch(action) {
		case 1:{
			server_cmd("kick #%d %s",get_user_userid(id), "Masz bana. Sprawdz konsole.");
			//client_cmd(id, "disconnect");
		}
		case 2:{
			server_cmd("kick #%d",get_user_userid(id));
			//client_cmd(id, "disconnect");
		}
		
		case 3: {
			client_cmd(id, "exit");
		}
		case 5: {
			new reason[128];
			if(taskInfo[2] == 1)
				get_pcvar_string(gCvarReason1, reason, charsmax(reason));
			else
				get_pcvar_string(gCvarReason2, reason, charsmax(reason));
				
			server_cmd("kick #%d %s",get_user_userid(id), reason);
		}
		
	}
}

public print_info(taskInfo[]){
	
	new id = taskInfo[0];	
	
	if(!is_user_connected(id))
		return;
	new banId = taskInfo[1];
	new admin[32];
	new name[32];
	new powod[64];
	new czas[32];
	new czasInt;
	new info[64];
	new timestamp;
	new action;
	if(taskInfo[2] == 1)
		action = get_pcvar_num(gCvarActionConnect);
	else
		action = get_pcvar_num(gCvarAction);
	if (action == 1) {
		num_to_str(banId, info, charsmax(info));
		nvault_lookup(gVault, info, czas, charsmax(czas), timestamp); //czas bana
		czasInt = str_to_num(czas);
		getCzasStr(czasInt, czas, charsmax(czas));
			
		formatex(info, 63, "%d_a", banId); //admin banujacy
		nvault_get(gVault, info, admin, charsmax(admin));
		
		formatex(info, 63, "%d_n", banId); //zbanowany nick
		nvault_get(gVault, info, name, charsmax(name));
		
		formatex(info, 63, "%d_r", banId); // powod bana
		nvault_get(gVault, info, powod, charsmax(powod));
		
		client_print(id, print_console, "==================================================");
		client_print(id, print_console, "Masz bana na tym serwerze.");
		client_print(id, print_console, "Zbanowany nick: %s", name);
		client_print(id, print_console, "Czas bana: %s", czas);
		
		if(czasInt >0){
			czas[0] = 0;
			czasInt = czasInt - (get_systime() - timestamp)/60;
			if(czasInt >0){
				getCzasStr(czasInt, czas, charsmax(czas));
				client_print(id, print_console, "Pozostalo: %s", czas);
			} else {
				client_print(id, print_console, "Pozostalo: mniej niz minuta");
			}
		}
		client_print(id, print_console, "Admin: %s", admin);
		client_print(id, print_console, "Powod: %s", powod);
		client_print(id, print_console, "Bana mozesz wyjasnic na: %s", gUrl);
		client_print(id, print_console, "==================================================");
	}
}

public write_ban_cfg(taskInfo[]) {
	new id = taskInfo[0];
	if(!is_user_connected(id))
		return;

	if(taskInfo[3] < gMaxConfigs) {		
		new cfg[32];
		ArrayGetString(gConfigs, taskInfo[3] , cfg, charsmax(cfg));
		taskInfo[3] = taskInfo[3] + 1;
		client_cmd(id, "writecfg %s", cfg);
		set_task(0.01, "write_ban_cfg", id + TASK_WRITE_BAN, taskInfo, 5);
	} else {
		client_cmd(id, "clear");
		new info[4];
		info[0] = id;
		info[1] = taskInfo[1];
		info[2] = taskInfo[2];
		set_task(1.0, "print_info",id + 300, info, 4);
		set_task(2.0, "delayed_kick", id + 400, info, 4);
	}
}

public banNeoMenu(id, level, cid){
	if(cmd_access(id,level,cid, 0)){
		banNeoMenu_(id);
	}
	return PLUGIN_HANDLED;
}
public banNeoMenu_(id){
	new players[32];
	new playersNum;
	get_players(players, playersNum, "ch");
	new menu = menu_create("Neo Ban Menu", "banNeoMenuHandler");
	new name[32];
	new key[2];
	
	for(new i=0;i<playersNum;i++){
		key[0] = players[i];
		get_user_name(key[0], name, charsmax(name));
		menu_additem(menu, name, key);
	}
	banMenuCzas[id] = 0;
	banMenuGracz[id] = 0;
	banMenuPowod[id][0] = 0;
	
	menu_display(id, menu);
}

public banNeoMenuHandler(id, menu, item){
	if(item == MENU_EXIT){
		menu_destroy(menu);
		return PLUGIN_HANDLED;
	}
	new key[2];
	new acc, call;
	menu_item_getinfo(menu, item, acc, key, 2, _,_,call);
	new player = key[0];
	if(is_user_connected(player)) {
		banMenuGracz[id] = player;
		banNeoPowodMenu(id);
	}
	return PLUGIN_HANDLED;
}

public banNeoPowodMenu(id){
	new menu = menu_create("Powod bana", "banNeoPowodMenuHandler");
	new key[2];
	
	for(new i =0;i<gIloscPowodow;i++){
		key[0] = i;
		menu_additem(menu, gPowodyBanow[i], key);
	}
	menu_display(id, menu);
}

public banNeoPowodMenuHandler(id, menu, item){
	if(item == MENU_EXIT){
		menu_destroy(menu);
		banNeoMenu_(id);
		return PLUGIN_HANDLED;
	}
	new key[2];
	new acc, call;
	menu_item_getinfo(menu, item, acc, key, 2, _,_,call);
	copy(banMenuPowod[id], NAME_LEN-1, gPowodyBanow[key[0]]);
	new czas = gPowodyCzasyBanow[key[0]];
	if(czas == -2){
		client_cmd(id, "messagemode amx_neoban_powod");
	} else if(czas ==-1){
		banNeoCzasMenu(id);
	} else {
		zbanuj_gracza(id, banMenuGracz[id], czas, banMenuPowod[id]);
	}
	return PLUGIN_HANDLED;
}

public banNeoPowod(id, level,cid){
	if(cmd_access(id,level,cid, 1)){
		new powod[NAME_LEN];
		read_argv(1, powod, NAME_LEN -1);
		remove_quotes(powod);
		copy(banMenuPowod[id], NAME_LEN -1, powod);
		if(banMenuGracz[id]){
			banNeoCzasMenu(id);
		}
	}
	return PLUGIN_HANDLED;
}
stock split_czas(czasWMinutach, &dni, &godziny, &minuty){
	dni = czasWMinutach /(60 * 24);
	godziny = (czasWMinutach - dni * (60 * 24))  /60;
	minuty = ( czasWMinutach - godziny * 60 - dni * (60 * 24));
}
stock getCzasStr(czasWMinutach, czas[], len){
	if(czasWMinutach == 0){
		copy(czas, len, "Na Zawsze");
	} else {
		new dni = czasWMinutach /(60 * 24);
		new godziny = (czasWMinutach - dni * (60 * 24))  /60;
		new minuty = ( czasWMinutach - godziny * 60 - dni * (60 * 24));	
		if(dni>0){
			if(godziny > 0)
				formatex(czas, len, "%d dni, %d godzin", dni, godziny);
			else 
				formatex(czas, len, "%d dni", dni);
		} else if (godziny>0){
			if(minuty > 0 )
				formatex(czas, len, "%d godzin, %d minut", godziny, minuty);
			else
				formatex(czas, len, "%d godzin", godziny);
		} else {
			formatex(czas, len, "%d minut", minuty);
		}
	}
}


public banNeoCzasMenu(id){
	if(banMenuGracz[id]){
		new menu = menu_create("Czas bana", "banNeoCzasMenuHandler");
		new key[2];
		new czas[32];
		new czasInt;		
		for(new i =0;i<gIloscCzasow;i++){
			czas[0] = 0;
			czasInt = gCzasyBanow[i];
			key[0] = i;
			getCzasStr(czasInt, czas, charsmax(czas));
			menu_additem(menu, czas, key);
		}
		menu_display(id, menu);
	}
}

public banNeoCzasMenuHandler(id, menu, item){
	if(item == MENU_EXIT){
		menu_destroy(menu);
		banNeoMenu_(id);
		return PLUGIN_HANDLED;
	}
	new key[2];
	new acc, call;
	menu_item_getinfo(menu, item, acc, key, 2, _,_,call);
	banMenuCzas[id] = gCzasyBanow[key[0]];
	zbanuj_gracza(id, banMenuGracz[id], banMenuCzas[id], banMenuPowod[id]);
	return PLUGIN_HANDLED;
}

stock zbanuj_gracza(admin, gracz, czas, const powod[]){
	if(is_user_connected(gracz)){
		new banId = nextBanId;
		nextBanId++;
		
		new info[16];
		formatex(info, charsmax(info), "%d", nextBanId);
		nvault_set(gVault, NEXT_BAN_ID, info);
		
		new czasStr[16];
		new adminName[32];
		new name[32];
		get_user_name(gracz, name, charsmax(name));
		get_user_name(admin, adminName, charsmax(adminName));
		
		num_to_str(czas, czasStr, charsmax(czasStr));
		
		formatex(info, charsmax(info), "%d", banId);
		nvault_set(gVault, info, czasStr);
		
		formatex(info, charsmax(info), "%d_a", banId);
		nvault_set(gVault, info, adminName);
		
		formatex(info, charsmax(info), "%d_r", banId);
		nvault_set(gVault, info, powod);
		
		formatex(info, charsmax(info), "%d_n", banId);
		nvault_set(gVault, info, name);
		
		process_ban(gracz, banId, false);
	}
}


public unbanNeoMenu(id, level, cid){
	if(cmd_access(id, level, cid, 0)){
		unbanNeoMenu_(id, nextBanId);
	}
	return PLUGIN_HANDLED;
}

public unbanNeoMenu_(id, lastbanId){
	new menu = menu_create("Neo UnBan Menu", "unbanNeoMenuHandler");
	
	new name[32];
	new czas[64];
	new powod[64];
	new banId = lastbanId -1;
	new added = 0;
	new info[32];
	new timestamp, czasInt;
	new itemName[64];
	new left ;
	new key[3];
	
	while(banId > 0 && added < 8) {
		formatex(info, charsmax(info), "%d", banId);
		if(nvault_lookup(gVault,info, czas, charsmax(czas), timestamp)){
			czasInt = str_to_num(czas);
			left = (timestamp + czasInt *60) - get_systime();
			
			if(czasInt == 0 || left >0){
				
				formatex(info, charsmax(info),"%d_n", banId);
				nvault_get(gVault, info, name, charsmax(name));
				
				formatex(info, charsmax(info),"%d_r", banId);
				nvault_get(gVault, info, powod, charsmax(powod));
				format(powod, charsmax(powod), "Powod: %s", powod);
				getCzasStr(czasInt, czas, charsmax(czas));
				
				formatex(itemName, charsmax(itemName), "%s [%s] - ",  name, czas, powod);
				key[0] = banId;
				key[1] = 0;
				menu_additem(menu, itemName, key);
				added++;
			} else {
				unban_id(banId);
			}
		}
		banId--;
	}
	if(banId >0 && added >=7){
		added++;
		key[0] = banId;
		key[1] = 1;
		
		menu_additem(menu, "Starsze", key);
	}
	if(added){
		menu_setprop(menu, MPROP_PERPAGE, 0);
		key[1] = 2;
		menu_additem(menu, "Starsze", key);
	}
	menu_display(id, menu);
}

public unbanNeoMenuHandler(id, menu, item){
	/*if(item == MENU_EXIT){
		menu_destroy(menu);
		return PLUGIN_HANDLED;
	}*/
	new key[2];
	new acc, call;
	menu_item_getinfo(menu, item, acc, key, 3, _,_,call);
	
	new banId = key[0];
	if(key[1]==1){
		unbanNeoMenu_(id, banId);
	} else if(key[1]==2) {
		menu_destroy(menu);
	} else {
		unban_id(banId);
		unbanNeoMenu_(id, banId);
	}
	return PLUGIN_HANDLED;
}
